%load_ext tensorboard
import wget
import os
import pickle
import tarfile
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly.express as px
**CIFAR10** и **CIFAR100** - классические наборы данных для решения задач классификации обучения с учителем. Принято рассматривать оба набора данных как единое целое, так как их отличие лишь в количестве классов на каждый набор (10 и 100 классов соответственно). Наборы данных были составлены экспертами из департамента Computer Science университета Торонто Alex Krizhevsky, Vinod Nair, и Geoffrey Hinton.
Набор данных CIFAR10 содержит 60000 цветных(RGB) изображений размером 32х32 пикселя из 10 классов. Количество изображений по классам распределено равномерно. Каждый класс содержит по 6000 соответствующих изображений. Набор данных разделен на train и test подмножества в соотношении 50000 и 10000 изображений. Эти классы полностью взаимоисключают друг друга. Между легковыми и грузовыми автомобилями нет перекрытия. "Автомобиль" включает в себя седаны, внедорожники и тому подобное. "Грузовик" включает в себя только большие грузовики. Ни то, ни другое не включает в себя пикапы.
| airplane | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| automobile | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| bird | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| cat | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| deer | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| dog | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| frog | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| horse | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| ship | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| truck | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Набор данных CIFAR100 мало отличается от своего младшего брата(CIFAR10) идеологически. Он содержит 100 классов, которые в свою очередь относятся к 20 суперклассам, которые их объединяют. Всего набор данных CIFAR100 содержит 60000 изображений из которых 50000 - тренировочный набор, 10000 - тестовый. Изображения распределены равномерно, соответственно каждый класс имеет по 600 экземпляров различных изображений.
| Superclass | Classes |
| aquatic mammals | beaver, dolphin, otter, seal, whale |
| fish | aquarium fish, flatfish, ray, shark, trout |
| flowers | orchids, poppies, roses, sunflowers, tulips |
| food containers | bottles, bowls, cans, cups, plates |
| fruit and vegetables | apples, mushrooms, oranges, pears, sweet peppers |
| household electrical devices | clock, computer keyboard, lamp, telephone, television |
| household furniture | bed, chair, couch, table, wardrobe |
| insects | bee, beetle, butterfly, caterpillar, cockroach |
| large carnivores | bear, leopard, lion, tiger, wolf |
| large man-made outdoor things | bridge, castle, house, road, skyscraper |
| large natural outdoor scenes | cloud, forest, mountain, plain, sea |
| large omnivores and herbivores | camel, cattle, chimpanzee, elephant, kangaroo |
| medium-sized mammals | fox, porcupine, possum, raccoon, skunk |
| non-insect invertebrates | crab, lobster, snail, spider, worm |
| people | baby, boy, girl, man, woman |
| reptiles | crocodile, dinosaur, lizard, snake, turtle |
| small mammals | hamster, mouse, rabbit, shrew, squirrel |
| trees | maple, oak, palm, pine, willow |
| vehicles 1 | bicycle, bus, motorcycle, pickup truck, train |
| vehicles 2 | lawn-mower, rocket, streetcar, tank, tractor |
Набор данных CIFAR100 и CIFAR10 предоставляются ввиде архива, который содержит 3 pickle файла в бинарном формате:
| Имя файла | Описание | |
| train | Содержит тренировочный набор данных в бинарном формате | |
| test | Содержит тестовый набор данных в бинарном формате | |
| meta | Содержит мета информацию о наборе данных. Например: список названий меток |
Pickle файлы с тренировочными и тестовыми данными имеют одинаковую структуру. Отличие лишь в самих данных и их количестве.
При распаковке pickle файла в Python окружение мы получим словарь(dict). Словарь по сути является таблицей вида:
dict {
str(filenames): List[str], size == N
str(batch_label): str
str(fine_labels): List[int], size == N
str(coarse_labels): List[int], size == N
str(data): np.ndarray((N, 3072))
}
| Ключ | Тип | Описание | |
| filenames | List of string | Уникальные имена файлов с изображением для идентификации конкретного изображения и сохранения. | |
| batch_label | String | Строковое описание к какому из пакетов принадлежит данный набор. В случае **CIFAR100** всегда является 'training batch 1 of 1' или 'testing batch 1 of 1' | |
| fine_labels | List of int | Идентификатор класса принадлежащий к i-му изображению. | |
| coarse_labels | List of int | Идентификатор суперкласса принадлежащий к i-му изображению. | |
| coarse_labels | Numpy ND Array | Числовые массивы описывающие изображения в формате RGB. (См. далее) |
По ключу data можно получить numpy.ndarray который содержит N "векторов". Каждый из векторов - отдельное изображение из набора данных.
>>> train_data, test_data, _ = load_CIFAR100()
>>> type(train_data) --> dict
>>> train_data.keys() --> dict_keys(['filenames', 'batch_label', 'fine_labels', 'coarse_labels', 'data'])
>>> data = train_data['data']
>>> data.shape --> (50000, 3072)
>>> data[0] --> array([255, 255, 255, ..., 10, 59, 79], dtype=uint8)
Каждый вектор можно представить в виде 32х32 RGB изображения. Первые 1024 элемента содержат в себе 32x32 значения для Red канала, следующие 1024 элемента - Blue, и последние - Green. Таким образом простым преобразованием numpy.reshape мы можем получить представление в виде 3x32x32:
>>> data = data.reshape(50000, 32, 32, 3) --> 50000 изображение формата HxWxC.
При распаковке pickle файла в Python окружение мы получим словарь(dict). Словарь по сути является таблицей вида:
dict {
str(fine_label_names): List[str], size == 20
str(coarse_label_names): List[str], size == 100
}
| Ключ | Тип | Описание | |
| fine_label_names | List of string | Строковые названия меток классов. Например: fine_label_names[0] == 'apple' | |
| coarse_label_names | List of string | Строковые названия меток суперклассов. Например: coarse_label_names[0] == 'aquatic_mammals' |
Традиционно эти два набора данных используются в качестве Benchmark для задачи классификации при крайне низком разрешении изображения. В качестве примеров статей можно привести этот список:
и во множестве других статей и работ.
Набор данных CIFAR100 предоставляется в 3х видах:
| Вид данных | Прямая ссылка | Размер | md5sum | |
| CIFAR-100 python version | Link | 161 MB | eb9058c3a382ffc7106e4002c42a8d85 | |
| CIFAR-100 matlab version | Link | 175 MB | 6a4bfa1dcd5c9453dda6bb54194911f4 | |
| CIFAR-100 binary version(C) | Link | 161 MB | 03b5dce01913d631647c71ecec9e9cb8 |
Загрузка данных из источника делится на 3 этапа:
CIFAR100_URL="https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz"
def download_CIFAR100() -> str:
"""
Загрузка архива с набором данных CIFAR-100.
Return:
str - путь к скачанному архиву.
"""
print("Start downloading dataset: CIFAR 100.")
print("Load from URL:", CIFAR100_URL)
archive_path = wget.download(CIFAR100_URL)
print()
print("Downloaded to archive:", archive_path)
return archive_path
def unpack_archive(archive_path: str) -> str:
"""
Распаковка архива по указанному пути.
Примечание: Архив должен иметь формат *.tar или *.tar.gz
Inputs:
archive_path [str] - Путь к архиву который нужно распаковать.
Return:
str - путь к директории куда был распакован архив
"""
readmode = 'r:'
if archive_path.endswith('.tar.gz'):
readmode += "gz"
tar = tarfile.open(archive_path, readmode)
tar.extractall()
tar.close()
os.remove(archive_path)
directory_with_data = os.path.abspath(archive_path).replace(".tar", "").replace(".gz", "")
print("Unpacked to:", directory_with_data)
return directory_with_data
def load_from_pickle_CIFAR100(directory_with_data: str):
"""
Загрузить набор данных CIFAR-100 из pickle файлов.
Inputs:
directory_with_data [str] - Директория в которой расположены файлы набора данных. Директория обязательно должна содержать файлы train, test, meta.
Return:
Tuple[Dict, Dict, Dict] - Распакованные наборы Train, Test, Meta.
"""
def unpickle(file):
import pickle
with open(file, 'rb') as fo:
dict = pickle.load(fo, encoding='latin1')
return dict
train_data = unpickle(os.path.join(directory_with_data, "train"))
test_data = unpickle(os.path.join(directory_with_data, "test"))
meta_data = unpickle(os.path.join(directory_with_data, "meta"))
return train_data, test_data, meta_data
Стадия загрузки и распаковки архива
archive = download_CIFAR100()
unpack_archive(archive)
Start downloading dataset: CIFAR 100. Load from URL: https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz 100% [..................................................] 169001437 / 169001437 Downloaded to archive: cifar-100-python.tar.gz Unpacked to: /home/ilya/work/MAI/MAI_AI_labs/lab_8/cifar-100-python
'/home/ilya/work/MAI/MAI_AI_labs/lab_8/cifar-100-python'
Стадия загрузки из Pickle
train_data, test_data, meta_data = load_from_pickle_CIFAR100("./cifar-100-python")
nrows = 3
ncols = 3
samples_ids = np.random.randint(0, len(train_data['data']), size=nrows * ncols).reshape(nrows, ncols)
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(15, 16))
for i in range(nrows):
for j in range(ncols):
sample_id = samples_ids[i, j]
sample = train_data['data'][sample_id].reshape((3, 32, 32)).transpose(1, 2, 0)
ax[i][j].imshow(sample)
title = f"{meta_data['coarse_label_names'][train_data['coarse_labels'][sample_id]]}:"
title += f"{meta_data['fine_label_names'][train_data['fine_labels'][sample_id]]}"
ax[i][j].set_title(title)
train_data['data'] = [sample for sample in train_data['data']]
test_data['data'] = [sample for sample in test_data['data']]
train_df = pd.DataFrame(data=train_data, columns=list(train_data.keys()))
train_df.drop(labels=['batch_label'], axis=1)
| filenames | fine_labels | coarse_labels | data | |
|---|---|---|---|---|
| 0 | bos_taurus_s_000507.png | 19 | 11 | [255, 255, 255, 255, 255, 255, 255, 255, 255, ... |
| 1 | stegosaurus_s_000125.png | 29 | 15 | [255, 253, 253, 253, 253, 253, 253, 253, 253, ... |
| 2 | mcintosh_s_000643.png | 0 | 4 | [250, 248, 247, 248, 249, 249, 248, 248, 247, ... |
| 3 | altar_boy_s_001435.png | 11 | 14 | [124, 131, 135, 138, 140, 144, 148, 152, 156, ... |
| 4 | cichlid_s_000031.png | 1 | 1 | [43, 32, 87, 127, 55, 48, 51, 87, 121, 113, 13... |
| ... | ... | ... | ... | ... |
| 49995 | tree_squirrel_s_000969.png | 80 | 16 | [130, 127, 131, 142, 127, 117, 138, 154, 156, ... |
| 49996 | tiger_beetle_s_000315.png | 7 | 7 | [167, 199, 193, 192, 195, 203, 188, 210, 200, ... |
| 49997 | bear_s_000631.png | 3 | 8 | [248, 240, 236, 234, 237, 236, 237, 238, 235, ... |
| 49998 | beetle_s_000411.png | 7 | 7 | [156, 151, 151, 151, 154, 154, 151, 151, 155, ... |
| 49999 | mako_s_001274.png | 73 | 1 | [31, 30, 31, 32, 31, 31, 32, 31, 30, 30, 31, 3... |
50000 rows × 4 columns
fig = px.histogram(train_df, x="fine_labels", title='Баланc классов(меток) по набору данных')
fig.show()
fig = px.histogram(train_df, x="coarse_labels", title='Баланc классов(меток) по набору данных')
fig.show()
Как видно из гистограмм выше, все классы и суперклассы распределены равномерно. При этом к каждой метке класса сопоставлено по 500 изображений из трегировочного набора, а к каждому суперклассу - 2500 изображений.
def extract_channel(array, channel_id):
return array.reshape(3, 32 * 32)[channel_id].reshape(32 * 32)
histograms = {
"red": np.zeros((256), dtype=np.int32),
"green": np.zeros((256), dtype=np.int32),
"blue": np.zeros((256), dtype=np.int32)
}
for i, row in train_df.iterrows():
data = row['data']
histograms['red'] += np.histogram(extract_channel(data, 0), bins=256)[0]
histograms['green'] += np.histogram(extract_channel(data, 1), bins=256)[0]
histograms['blue'] += np.histogram(extract_channel(data, 2), bins=256)[0]
df = pd.DataFrame(data=histograms, index=[i for i in range(256)])
px.bar(df, title='Распределение пикселей по набору данных')
Используется простейшая сверточная нейронная сеть для решения задачи классификации на наборе данных CIFAR-100.
import datetime
import numpy as np
from sklearn import metrics
import tensorflow as tf
import keras
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
Изображения приводятся к формату np.ndarray((3, 32, 32)). К меткам применяется One-hot encoding.
train_dec, test_dec, meta_dec = load_from_pickle_CIFAR100("./cifar-100-python")
train_data = np.array([train_dec['data'][i].reshape(3, 32, 32).transpose(1, 2, 0) for i in range(len(train_dec['data']))])
test_data = np.array([test_dec['data'][i].reshape(3, 32, 32).transpose(1, 2, 0) for i in range(len(test_dec['data']))])
train_labels = np.array([[label] for label in train_dec['coarse_labels']], dtype=np.int64)
test_labels = np.array([[label] for label in test_dec['coarse_labels']], dtype=np.int64)
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
print('==================== Prepared data shapes =================')
print('Train data shape:', train_data.shape)
print('Test data shape:', test_data.shape)
print('Train labels shape:', train_labels.shape)
print('Test labels shape:', test_labels.shape)
==================== Prepared data shapes ================= Train data shape: (50000, 32, 32, 3) Test data shape: (10000, 32, 32, 3) Train labels shape: (50000, 20) Test labels shape: (10000, 20)
Модель имеет простейший препроцессинг: Нормализация данных. Формула: $X_i = \frac{X_i}{255}$ Выход модели представляет собой вектор из 20 float значений которые обладают свойством: $\sum_{i=1}^{20}x_i = 1$, что позволяет интерпретировать этот вектор как вектор оценок вероятностей принадлежности изображения к классу определенный моделью.
class ModelPipeline:
"""
Базовый класс реализующий пайплайн модели классификации над набором данных CIFAR-100 [Суперклассы].
"""
def __init__(self, weights_path: str=''):
"""
Инициализация модели.
Inputs:
weights_path [str] - Путь к файлу с весами модели. Если он не указан, то инициализация пройдет с нулевыми весами.
Default: ''
"""
self.tfmodel = keras.Sequential()
self.model_weights_path = weights_path
self.__data_scale__ = 255.0
self.__init_model__()
def __init_model__(self):
self.tfmodel.add(Conv2D(32, kernel_size = (3,3), activation='relu', padding = 'same', input_shape = (32,32,3)))
self.tfmodel.add(MaxPooling2D((2, 2)))
self.tfmodel.add(Conv2D(64, kernel_size = (3,3), activation='relu', padding = 'same'))
self.tfmodel.add(MaxPooling2D((2, 2)))
self.tfmodel.add(Conv2D(128, kernel_size = (3,3), activation='relu', padding = 'same'))
self.tfmodel.add(MaxPooling2D((2, 2)))
self.tfmodel.add(Flatten())
self.tfmodel.add(Dense(128, activation='relu'))
self.tfmodel.add(Dense(20, activation='softmax'))
print("Inited model:")
self.tfmodel.summary()
optimizer = Adam(learning_rate=0.003)
self.tfmodel.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
if self.model_weights_path:
self.tfmodel.load_weights(self.model_weights_path)
print("Model weights loaded:", self.model_weights_path)
def __preprocessing__(self, sample):
return sample / self.__data_scale__
def evaluate(self, data: np.ndarray, labels: np.ndarray):
"""
Валидирование модели.
Inputs:
data [np.ndarray] - Набор из изображений для валидации. Должен состоять из N изображений 32х32х3.
labels [np.ndarray] - Соответсвующая набору data разметка данных по суперклассам.
Return:
Tuple[float, float] - Кортеж:
0 [float] - Значение Loss функции для проведенного замера точности.
1 [float] - Значение Accuracy для проведенного замера точности.
"""
return self.tfmodel.evaluate(self.__preprocessing__(data), labels)
def prediction(self, data: np.ndarray):
"""
Inputs:
data [np.ndarray] - Набор из изображений для предсказания меток. Должен состоять из N изображений 32x32x3.
Return:
np.ndarray - Массив вида np.ndarray(N, 20). По первой оси - индекс соответствующий изображению из data.
По второй оси - 20 float элементов. i-й элемент показывает оценку вероятности принадлежности изображения к i-ой метке.
"""
return self.tfmodel.predict(self.__preprocessing__(data))
MODEL_WEIGTHS_PATH = r'./model/CNN_100.hdf5'
pipeline = ModelPipeline(MODEL_WEIGTHS_PATH)
Inited model:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 32, 32, 32) 896
max_pooling2d (MaxPooling2D (None, 16, 16, 32) 0
)
conv2d_1 (Conv2D) (None, 16, 16, 64) 18496
max_pooling2d_1 (MaxPooling (None, 8, 8, 64) 0
2D)
conv2d_2 (Conv2D) (None, 8, 8, 128) 73856
max_pooling2d_2 (MaxPooling (None, 4, 4, 128) 0
2D)
flatten (Flatten) (None, 2048) 0
dense (Dense) (None, 128) 262272
dense_1 (Dense) (None, 20) 2580
=================================================================
Total params: 358,100
Trainable params: 358,100
Non-trainable params: 0
_________________________________________________________________
Model weights loaded: ./model/CNN_100.hdf5
2022-12-17 01:52:25.416051: E tensorflow/compiler/xla/stream_executor/cuda/cuda_driver.cc:267] failed call to cuInit: CUDA_ERROR_SYSTEM_DRIVER_MISMATCH: system has unsupported display driver / cuda driver combination 2022-12-17 01:52:25.416092: I tensorflow/compiler/xla/stream_executor/cuda/cuda_diagnostics.cc:169] retrieving CUDA diagnostic information for host: ilya-lenovo-pad 2022-12-17 01:52:25.416101: I tensorflow/compiler/xla/stream_executor/cuda/cuda_diagnostics.cc:176] hostname: ilya-lenovo-pad 2022-12-17 01:52:25.416226: I tensorflow/compiler/xla/stream_executor/cuda/cuda_diagnostics.cc:200] libcuda reported version is: 525.60.11 2022-12-17 01:52:25.416258: I tensorflow/compiler/xla/stream_executor/cuda/cuda_diagnostics.cc:204] kernel reported version is: NOT_FOUND: could not find kernel module information in driver version file contents: "NVRM version: NVIDIA UNIX Open Kernel Module for x86_64 520.56.06 Release Build (dvs-builder@U16-T12-10-2) Thu Oct 6 21:33:54 UTC 2022 GCC version: gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1) " 2022-12-17 01:52:25.416759: I tensorflow/core/platform/cpu_feature_guard.cc:193] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 FMA To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
loss, accuracy = pipeline.evaluate(test_data, test_labels)
print('Test accuracy = '+str(accuracy)+' Test Loss = '+str(loss))
313/313 [==============================] - 2s 7ms/step - loss: 1.8203 - accuracy: 0.4437 Test accuracy = 0.44369998574256897 Test Loss = 1.8203390836715698
predicts = pipeline.prediction(test_data)
predictions_labels = [(meta_dec['coarse_label_names'][np.argmax(predicts[i])], np.max(predicts[i])) for i in range(len(predicts))]
313/313 [==============================] - 2s 6ms/step
nrows = 3
ncols = 3
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(15, 16))
for i in range(nrows):
for j in range(ncols):
idx = i * ncols + j
sample = test_data[idx]
ax[i][j].imshow(sample)
title = f"{predictions_labels[idx][0]}. Conf: {int(round(predictions_labels[idx][1], 2) * 100)}%"
ax[i][j].set_title(title)
На простом примере продемонстирую как используется Tensorboard доска
train_dec, test_dec, meta_dec = load_from_pickle_CIFAR100("./cifar-100-python")
train_data = np.array([train_dec['data'][i].reshape(3, 32, 32).transpose(1, 2, 0) for i in range(len(train_dec['data']))])
test_data = np.array([test_dec['data'][i].reshape(3, 32, 32).transpose(1, 2, 0) for i in range(len(test_dec['data']))])
train_labels = np.array([[label] for label in train_dec['coarse_labels']], dtype=np.int64)
test_labels = np.array([[label] for label in test_dec['coarse_labels']], dtype=np.int64)
print('Train data shape:', train_data.shape)
print('Test data shape:', test_data.shape)
print('Train labels shape:', train_labels.shape)
print('Test labels shape:', test_labels.shape)
Train data shape: (50000, 32, 32, 3) Test data shape: (10000, 32, 32, 3) Train labels shape: (50000, 1) Test labels shape: (10000, 1)
def create_model():
return tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", padding="same", input_shape=(32, 32, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu", padding="same"),
tf.keras.layers.Conv2D(64, kernel_size=(1, 1), activation="relu", padding="same"),
tf.keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu", padding="same"),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation="relu", padding="same"),
tf.keras.layers.Conv2D(128, kernel_size=(1, 1), activation="relu", padding="same"),
tf.keras.layers.Conv2D(128, kernel_size=(3, 3), activation="relu", padding="same"),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(20, activation='softmax')
])
def train_model():
model = create_model()
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
logdir = os.path.join("logs", datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
tensorboard_callback = tf.keras.callbacks.TensorBoard(logdir, histogram_freq=1)
model.fit(x=x_train,
y=y_train,
epochs=3,
validation_data=(x_test, y_test),
callbacks=[tensorboard_callback])
return model
x_train, x_test = train_data / 255.0, test_data / 255.0
y_train, y_test = train_labels, test_labels
model = train_model()
Epoch 1/3 1563/1563 [==============================] - 103s 65ms/step - loss: 2.4923 - accuracy: 0.2248 - val_loss: 2.2773 - val_accuracy: 0.2929 Epoch 2/3 1563/1563 [==============================] - 104s 67ms/step - loss: 2.0952 - accuracy: 0.3497 - val_loss: 2.0446 - val_accuracy: 0.3686 Epoch 3/3 1563/1563 [==============================] - 105s 67ms/step - loss: 1.8867 - accuracy: 0.4107 - val_loss: 1.8778 - val_accuracy: 0.4166
%tensorboard --logdir ./logs/
ERROR: Could not find `tensorboard`. Please ensure that your PATH contains an executable `tensorboard` program, or explicitly specify the path to a TensorBoard binary by setting the `TENSORBOARD_BINARY` environment variable.

В качестве сложного препроцессинга был выбран препроцессинг повышения разрешения изображений. Используется модель из репозитория Real-ESRGAN.
Модель повышает разрешение изображения в 4 раза с помощью нейросетевых методов.
Скачивание весов модели
!wget https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth -P weights
import cv2
import glob
import os
from basicsr.archs.rrdbnet_arch import RRDBNet
from basicsr.utils.download_util import load_file_from_url
from realesrgan import RealESRGANer
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
class Enhancer:
def __init__(self, weights_path='weights/RealESRGAN_x4plus.pth'):
self.model_path = weights_path
self.tile = 0
self.tile_pad = 10
self.pre_pad = 0
self.half = False
self.gpu_id = None
self.outscale = 4
self.__is_inited__ = False
self.__upsampler__ = None
def init(self):
self.__is_inited__ = True
model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
netscale = 4
file_url = ['https://github.com/xinntao/Real-ESRGAN/releases/download/v0.1.0/RealESRGAN_x4plus.pth']
# restorer
self.__upsampler__ = RealESRGANer(
scale=netscale,
model_path=self.model_path,
dni_weight=None,
model=model,
tile=self.tile,
tile_pad=self.tile_pad,
pre_pad=self.pre_pad,
half=self.half,
gpu_id=self.gpu_id)
def infer(self, data: np.ndarray) -> np.ndarray:
if not self.__is_inited__:
raise RuntimeError("Please run Enhancer.init() before usage.")
if len(data.shape) == 3:
output, _ = self.__upsampler__.enhance(data, outscale=self.outscale)
return output
elif len(data.shape) == 4:
outputs = list()
for sample in data:
output, _ = self.__upsampler__.enhance(sample, outscale=self.outscale)
outputs.append(output)
return np.array(outputs)
return None
/home/ilya/anaconda3/envs/MAI-AI-CW/lib/python3.10/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
enhancer = Enhancer()
enhancer.init()
output = enhancer.infer(train_data[:10])
/home/ilya/anaconda3/envs/MAI-AI-CW/lib/python3.10/site-packages/torch/cuda/__init__.py:88: UserWarning: CUDA initialization: Unexpected error from cudaGetDeviceCount(). Did you run some cuda functions before calling NumCudaDevices() that might have already set an error? Error 803: system has unsupported display driver / cuda driver combination (Triggered internally at ../c10/cuda/CUDAFunctions.cpp:109.)
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=6, ncols=2, figsize=(5, 15))
for i in range(6):
ax[i][0].tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
ax[i][1].tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
ax[i][0].set_title('before')
ax[i][1].set_title('after')
ax[i][0].imshow(train_data[i])
ax[i][1].imshow(output[i])